#pragma once

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <memory.h>
#include <memory>
#include <list>
#include <map>
#include <vector>
#include <functional>
#include <unordered_map>

#include "http_parser.h"


namespace Ark
{
	struct CaseInsensitiveCompare
	{
		int operator () (const std::string& s1, const std::string& s2) const {
#ifdef _WIN32
			return _stricmp(s1.c_str(), s2.c_str());
#else
			return strcasecmp(s1.c_str(), s2.c_str());
#endif // _WIN32
		}
	};
	typedef std::map<std::string, std::list<std::string>, CaseInsensitiveCompare> HTTPHeaders;


	class HTTPParser
	{
		typedef HTTPParser self;
	public:
		enum PARSER_TYPE {
			PARSER_NONE = 0,
			PARSER_REQUEST = 1,
			PARSER_RESPONSE = 2,
		};

		HTTPParser(PARSER_TYPE type);
		~HTTPParser();

	public:
		typedef std::function<void(const void* data, size_t len)> OnBodyFunction;

		int Parse(const void* data, int size);
		int GetState() const;
		int GetStatusCode() const;
		std::string GetHeader(const char* name);
		PARSER_TYPE GetType() const;
		const HTTPHeaders& GetHeaders() const;
		
		void SetOnBody(const OnBodyFunction& onBody);

	private:
		//http parser callbacks
		static int on_message_begin(http_parser* parser);
		static int on_status(http_parser* parser, const char *at, size_t length);
		static int on_header_field(http_parser* parser, const char* at, size_t length);
		static int on_header_value(http_parser* parser, const char* at, size_t length);
		static int on_headers_complete(http_parser* parser);
		static int on_url(http_parser* parser, const char* at, size_t length);
		static int on_body(http_parser* parser, const char* at, size_t length);
		static int on_chunk_header(http_parser* parser);
		static int on_chunk_complete(http_parser* parser);
		static int32_t on_message_complete(http_parser* parser);
	private:
		
		void _OnRecvHeader();
		void _OnRecvBody(const void* data, size_t len);

	private:
		enum PARSE_STATE
		{
			STATE_NONE = 0,
			STATE_FAIL = 1,
			STATE_RECV_DONE = 2,

			STATE_RECV_BEGIN = 3,
			STATE_RECV_HEADER_NAME = 4,
			STATE_RECV_HEADER_VALUE = 5,
			STATE_RECV_BODY = 6,
		};

		
		PARSER_TYPE _type = PARSER_NONE;
		int _statusCode = 0;
		std::string _url;
		std::string _statusText;
		HTTPHeaders _headers;

		struct  
		{
			int state = STATE_NONE;
			std::unique_ptr<http_parser> parser;
			http_parser_settings settings;
			std::string headerName;
			std::string headerValue;
		} _context;

		OnBodyFunction _onBody;
	};
}